package com.anjiplus.template.gaea.gateway.filter;

import com.anji.plus.gaea.GaeaProperties;
import com.anji.plus.gaea.cache.CacheHelper;
import com.anji.plus.gaea.constant.Enabled;
import com.anji.plus.gaea.constant.GaeaConstant;
import com.anji.plus.gaea.constant.GaeaKeyConstant;
import com.anji.plus.gaea.utils.GaeaUtils;
import com.anji.plus.gaea.utils.JwtBean;
import com.anjiplus.template.gaea.gateway.utils.GaeaWebFluxUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.concurrent.TimeUnit;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;

/**
 * 验证是否登录
 * @author lr
 * @since 2021-03-01
 */
public class GlobalSecurityAuthenticationFilter implements GlobalFilter, Ordered {


    @Autowired
    private GaeaProperties gaeaProperties;

    @Autowired
    private JwtBean jwtBean;

    @Autowired
    private CacheHelper cacheHelper;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //判断是否设置跳过标识
        Enabled attributeOrDefault = exchange.getAttributeOrDefault(SkipAuthenticationGatewayFilterFactory.SKIP, Enabled.NO);
        if (attributeOrDefault == Enabled.YES) {
            return chain.filter(exchange);
        }

        //判断白名单
        URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

        //白名单
        if (GaeaUtils.matchPath(gaeaProperties.getSecurity().getWhiteList(), requestUrl.getPath())) {
            //当符合白名单时，直接放过且添加放过标识，让后续过滤器不拦截
            exchange.getAttributes().put(GaeaWebFluxUtils.SKIP, 1);
            return chain.filter(exchange);
        }
        ServerHttpRequest request = exchange.getRequest();

        //token
        String token = request.getHeaders().getFirst(GaeaConstant.Authorization);

        //当toke为空时，直接返回未登录
        if (StringUtils.isBlank(token)) {
            return tokenExpireResult(exchange);
        }

        //校验token的有效性
        String username = null;
        try {
            username = jwtBean.getUsername(token);
        } catch (Exception e) {

        }
        if (StringUtils.isBlank(username)) {
            return tokenExpireResult(exchange);
        }

        String tokenKey = GaeaKeyConstant.USER_LOGIN_TOKEN + username + GaeaConstant.REDIS_SPLIT + jwtBean.getUUID(token);

        //验证token是否有效
        if (!cacheHelper.exist(tokenKey) || !StringUtils.equals(token,cacheHelper.stringGet(tokenKey))) {
            return tokenExpireResult(exchange);
        }

        //刷新token超时时间
        cacheHelper.expire(tokenKey, TimeUnit.MINUTES, gaeaProperties.getSecurity().getJwtTokenTimeout());
        //将用户名放入request attributes
        exchange.getAttributes().put(GaeaWebFluxUtils.USER_NAME, username);
        String ipAddr=getIpAddr(request);
        ServerHttpRequest host = exchange.getRequest().mutate().header(GaeaConstant.SOURCE_IP, ipAddr).build();
        //将现在的request 变成 change对象
        return chain.filter(exchange.mutate().request(host).build());
    }

    /**
     * 返回结果
     * @param exchange
     * @return
     */
    private Mono<Void> tokenExpireResult(ServerWebExchange exchange) {
        return GaeaWebFluxUtils.getFilterResult(exchange, "User.credentials.expired", "登录凭证过期或未登录");
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE -2;
    }


    /**获取ip地址
     * @param request
     * @return
     */
    public String getIpAddr(ServerHttpRequest request) {
        String ip = request.getHeaders().getFirst("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeaders().getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeaders().getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        if(ip.contains(",")){
            String[] ipArray = ip.split(",");
            String userIP = ipArray[0];
            ip = userIP.trim();
        }
        return ip;
    }

}
